/**
 * @file websocketclient.h
 * @brief WebSocket客户端类头文件 - 处理与游戏服务器的实时通信
 *
 * WebSocketClient是应用程序的实时通信核心，提供：
 * - 与游戏服务器的WebSocket连接管理
 * - 消息的发送和接收处理
 * - 自动重连和心跳机制
 * - 连接状态监控和错误处理
 * - 基于Qt6的高性能异步通信
 */

#ifndef WEBSOCKETCLIENT_H
#define WEBSOCKETCLIENT_H

#include <QObject>              // Qt对象基类
#include <QWebSocket>           // WebSocket客户端
#include <QTimer>               // 定时器，用于心跳和重连
#include <QJsonObject>          // JSON对象处理
#include <QJsonArray>           // JSON数组处理
#include <QJsonDocument>        // JSON文档处理
#include <QUrl>                 // URL处理
#include <QUrlQuery>            // URL查询参数
#include <QNetworkProxy>        // 网络代理支持
#include <QNetworkRequest>      // 网络请求
#include <QSslConfiguration>    // SSL配置
#include <QSslError>            // SSL错误
#include <QMutex>               // 线程安全
#include <QQueue>               // 消息队列
#include <QAbstractSocket>      // Socket错误类型

/**
 * @class WebSocketClient
 * @brief WebSocket客户端类
 *
 * 封装所有WebSocket通信相关的功能，提供完整的实时通信解决方案。
 * 支持自动重连、心跳检测、消息队列、SSL加密等高级特性。
 */
class WebSocketClient : public QObject
{
    Q_OBJECT  // 启用Qt元对象系统

public:
    /**
     * @enum ConnectionState
     * @brief 连接状态枚举
     */
    enum ConnectionState {
        Disconnected = 0,       ///< 已断开连接
        Connecting,             ///< 正在连接
        Connected,              ///< 已连接
        Authenticated,          ///< 已认证（可以发送游戏消息）
        Reconnecting,           ///< 正在重连
        Error                   ///< 连接错误
    };
    Q_ENUM(ConnectionState)

    /**
     * @struct ConnectionConfig
     * @brief 连接配置结构
     */
    struct ConnectionConfig {
        QString serverUrl;              ///< 服务器URL
        QString gameToken;              ///< WebSocket连接认证令牌（access_token）
        QString sessionToken;           ///< WebSocket消息认证令牌（session_token）
        QString playerId;               ///< 玩家ID
        int heartbeatInterval = 30000;  ///< 心跳间隔（毫秒）
        int reconnectInterval = 5000;   ///< 重连间隔（毫秒）
        int maxReconnectAttempts = 5;   ///< 最大重连次数
        bool enableCompression = true;  ///< 启用压缩
        bool enableSSL = false;         ///< 启用SSL
        QStringList protocols;          ///< 支持的协议列表
    };

    explicit WebSocketClient(QObject *parent = nullptr);
    ~WebSocketClient();

    // === 连接管理 ===
    /**
     * @brief 连接到游戏服务器
     * @param config 连接配置
     * @return 是否成功开始连接
     */
    bool connectToServer(const ConnectionConfig &config);

    /**
     * @brief 断开连接
     * @param reason 断开原因
     */
    void disconnectFromServer(const QString &reason = QString());

    /**
     * @brief 获取当前连接状态
     * @return 连接状态
     */
    ConnectionState getConnectionState() const { return m_connectionState; }

    /**
     * @brief 是否已连接
     * @return true表示已连接并认证
     */
    bool isConnected() const { return m_connectionState == Authenticated; }

    // === 消息发送 ===
    /**
     * @brief 发送JSON消息
     * @param message JSON消息对象
     * @return 是否成功发送
     */
    bool sendMessage(const QJsonObject &message);

    /**
     * @brief 发送文本消息
     * @param message 文本消息
     * @return 是否成功发送
     */
    bool sendTextMessage(const QString &message);

    // === 游戏专用消息方法 ===
    /**
     * @brief 发送认证消息
     * @param token 游戏令牌
     * @param playerId 玩家ID
     */
    void sendAuthentication(const QString &token, const QString &playerId);

    /**
     * @brief 创建游戏房间
     * @param roomName 房间名称
     * @param config 房间配置
     */
    void createRoom(const QString &roomName, const QJsonObject &config);

    /**
     * @brief 加入游戏房间
     * @param roomId 房间ID
     */
    void joinRoom(const QString &roomId);

    /**
     * @brief 离开游戏房间
     */
    void leaveRoom();

    /**
     * @brief 改变移动方向
     * @param direction 方向（0=上，1=右，2=下，3=左）
     */
    void changeDirection(int direction);

    /**
     * @brief 发送聊天消息
     * @param message 聊天内容
     */
    void sendChatMessage(const QString &message);

    // === 配置管理 ===
    /**
     * @brief 设置自动重连
     * @param enabled 是否启用
     */
    void setAutoReconnect(bool enabled) { m_autoReconnect = enabled; }

    /**
     * @brief 设置心跳间隔
     * @param interval 间隔时间（毫秒）
     */
    void setHeartbeatInterval(int interval);

    /**
     * @brief 获取连接统计信息
     * @return 统计信息JSON对象
     */
    QJsonObject getConnectionStats() const;

signals:
    // === 连接状态信号 ===
    /**
     * @brief 连接状态改变信号
     * @param state 新的连接状态
     */
    void connectionStateChanged(ConnectionState state);

    /**
     * @brief 连接成功信号
     */
    void connected();

    /**
     * @brief 断开连接信号
     * @param reason 断开原因
     */
    void disconnected(const QString &reason);

    /**
     * @brief 认证成功信号
     * @param playerInfo 玩家信息
     */
    void authenticated(const QJsonObject &playerInfo);

    /**
     * @brief 认证失败信号
     * @param error 错误信息
     */
    void authenticationFailed(const QString &error);

    /**
     * @brief 连接错误信号
     * @param error 错误信息
     */
    void connectionError(const QString &error);

    /**
     * @brief 游戏业务错误信号
     * @param errorCode 错误代码
     * @param errorMessage 错误消息
     */
    void gameError(const QString &errorCode, const QString &errorMessage);

    // === 消息接收信号 ===
    /**
     * @brief 收到消息信号
     * @param message JSON消息对象
     */
    void messageReceived(const QJsonObject &message);

    /**
     * @brief 收到欢迎消息信号
     * @param welcomeData 欢迎消息数据
     */
    void welcomeMessageReceived(const QJsonObject &welcomeData);

    /**
     * @brief 游戏状态更新信号
     * @param gameState 游戏状态
     */
    void gameStateUpdated(const QJsonObject &gameState);

    /**
     * @brief 玩家加入信号
     * @param playerId 玩家ID
     * @param playerName 玩家名称
     */
    void playerJoined(const QString &playerId, const QString &playerName);

    /**
     * @brief 玩家离开信号
     * @param playerId 玩家ID
     */
    void playerLeft(const QString &playerId);

    /**
     * @brief 房间创建成功信号
     * @param roomId 房间ID
     * @param roomInfo 房间信息
     */
    void roomCreated(const QString &roomId, const QJsonObject &roomInfo);

    /**
     * @brief 加入房间成功信号
     * @param roomId 房间ID
     */
    void roomJoined(const QString &roomId);

    /**
     * @brief 聊天消息信号
     * @param senderId 发送者ID
     * @param senderName 发送者名称
     * @param message 消息内容
     */
    void chatMessageReceived(const QString &senderId, const QString &senderName, const QString &message);

    /**
     * @brief 游戏开始信号
     */
    void gameStarted();

    /**
     * @brief 游戏结束信号
     * @param results 游戏结果
     */
    void gameEnded(const QJsonObject &results);

private slots:
    // === WebSocket事件处理 ===
    void onWebSocketConnected();
    void onWebSocketDisconnected();
    void onWebSocketError(QAbstractSocket::SocketError error);
    void onWebSocketTextMessageReceived(const QString &message);
    void onWebSocketBinaryMessageReceived(const QByteArray &data);
    void onWebSocketSslErrors(const QList<QSslError> &errors);

    // === 定时器事件处理 ===
    void onHeartbeatTimer();
    void onReconnectTimer();
    void onMessageQueueTimer();

private:
    // === 内部方法 ===
    bool doConnect();                   ///< 执行实际连接（不重置重连计数器）

    // === 核心组件 ===
    QWebSocket *m_webSocket;            ///< WebSocket客户端对象
    ConnectionConfig m_config;          ///< 连接配置
    ConnectionState m_connectionState;  ///< 当前连接状态

    // === 定时器 ===
    QTimer *m_heartbeatTimer;          ///< 心跳定时器
    QTimer *m_reconnectTimer;          ///< 重连定时器
    QTimer *m_messageQueueTimer;       ///< 消息队列处理定时器

    // === 状态管理 ===
    bool m_autoReconnect;              ///< 是否自动重连
    int m_reconnectAttempts;           ///< 当前重连次数
    QString m_sessionId;               ///< 会话ID
    QString m_currentRoomId;           ///< 当前房间ID
    QString m_temporaryPlayerId;       ///< 临时玩家ID（从欢迎消息获取）

    // === 消息队列 ===
    QQueue<QJsonObject> m_messageQueue; ///< 待发送消息队列
    QMutex m_queueMutex;               ///< 队列互斥锁
    bool m_queueEnabled;               ///< 是否启用消息队列

    // === 统计信息 ===
    qint64 m_connectTime;              ///< 连接时间戳
    qint64 m_lastHeartbeat;            ///< 最后心跳时间
    int m_messagesSent;                ///< 已发送消息数
    int m_messagesReceived;            ///< 已接收消息数

    // === 私有方法 ===
    void setupWebSocket();
    void setupTimers();
    void setState(ConnectionState state);
    void processMessage(const QJsonObject &message);
    void handleWelcomeMessage(const QJsonObject &message);
    void handleAuthenticationResponse(const QJsonObject &response);
    void handlePingMessage(const QJsonObject &message);
    void handleGameMessage(const QJsonObject &message);
    void sendHeartbeat();
    void startReconnect();
    void processMessageQueue();
    void queueMessage(const QJsonObject &message);
    QString generateMessageId() const;
    void updateConnectionStats();
    void logMessage(const QString &direction, const QJsonObject &message);
};

#endif // WEBSOCKETCLIENT_H
